package systemService

import (
	"github.com/Sir-yuChen/funAnalyse/global"
	"github.com/Sir-yuChen/funAnalyse/global/constant"
	"github.com/Sir-yuChen/funAnalyse/model/common/ApiReturn"
	"github.com/Sir-yuChen/funAnalyse/model/request"
	"github.com/Sir-yuChen/funAnalyse/utils"
	"github.com/shirou/gopsutil/cpu"
	"github.com/shirou/gopsutil/disk"
	"github.com/shirou/gopsutil/host"
	"github.com/shirou/gopsutil/load"
	"github.com/shirou/gopsutil/mem"
	"go.uber.org/zap"
	"net"
	"time"
)

/*
	gopsutil将不同的功能划分到不同的子包中：
		cpu：CPU 相关；
		disk：磁盘相关；
		docker：docker 相关；
		host：主机相关；
		mem：内存相关；
		net：网络相关；
		process：进程相关；
		winservices：Windows 服务相关。

*/
type SysMoniterService struct{}

func (s SysMoniterService) SysMoniter(req *request.MoniterRequest) ApiReturn.ApiReturnCode {
	ok := ApiReturn.OK
	relutMap := map[string]interface{}{}
	switch req.Type {
	case constant.SYS_MONITER_CPU:
		//1.CPU
		moniterCpu := MoniterCpu()
		relutMap["CPU"] = moniterCpu
		break
	case constant.SYS_MONITER_MEM:
		moniterMem := MoniterMem()
		relutMap["Mem"] = moniterMem
		break
	case constant.SYS_MONITER_DISK:
		moniterDisk := MoniterDisk()
		relutMap["Disk"] = moniterDisk
		break
	case constant.SYS_MONITER_PROCESS:
		break
	case constant.SYS_MONITER_NET:
		ip, _ := GetLocalIP()
		relutMap["IP"] = ip
		break
	case constant.SYS_MONITER_WIN:
		break
	case constant.SYS_MONITER_LOAD:
		moniterLoad := MoniterLoad()
		relutMap["LoadAvg"] = moniterLoad
		break
	case constant.SYS_MONITER_HOST:
		moniterHost := MoniterHost()
		relutMap["Host"] = moniterHost
		break
	default:
		moniterHost := MoniterHost()
		relutMap["Host"] = moniterHost
		moniterCpu := MoniterCpu()
		relutMap["CPU"] = moniterCpu
		moniterMem := MoniterMem()
		relutMap["Mem"] = moniterMem
		moniterDisk := MoniterDisk()
		relutMap["Disk"] = moniterDisk
		moniterLoad := MoniterLoad()
		relutMap["LoadAvg"] = moniterLoad
		ip, _ := GetLocalIP()
		relutMap["IP"] = ip
	}
	ok.Data = relutMap
	return ok
}

// MoniterCpu cpu
func MoniterCpu() map[string]interface{} {
	relut := map[string]interface{}{}
	//Counts(logical bool)：传入false，返回物理核数，传入true，返回逻辑核数；
	physicalCnt, _ := cpu.Counts(false) //物理cpu核数
	logicalCnt, _ := cpu.Counts(true)   //逻辑核数
	relut["physicalCnt"] = physicalCnt
	relut["logicalCnt"] = logicalCnt

	//Percent(interval time.Duration, percpu bool)：表示获取interval时间间隔内的 CPU 使用率，percpu为false时，获取总的 CPU 使用率，percpu为true时，分别获取每个 CPU 的使用率，返回一个[]float64类型的值。
	totalPercent, _ := cpu.Percent(time.Second, false) //秒内cpu总使用率
	perPercents, _ := cpu.Percent(time.Second, true)   //秒内每个cpu使用率 []float64
	relut["cpuUsedTotalPercent"] = totalPercent
	relut["cpuUsedUnitPercent"] = perPercents

	//cpu详情
	cpuInfos, _ := cpu.Info()
	relut["cpuInfos"] = cpuInfos
	return relut
}

// MoniterDisk 子包disk用于获取磁盘信息。disk可获取 IO 统计、分区和使用率信息
func MoniterDisk() map[string]interface{} {
	relut := map[string]interface{}{}
	//io
	//调用disk.IOCounters()函数，返回的 IO 统计信息用map[string]IOCountersStat类型表示。每个分区一个结构，键为分区名，值为统计信息。这里摘取统计结构的部分字段，主要有读写的次数、字节数和时间
	//disk.IOCounters()可传入可变数量的字符串参数用于标识分区，此参数在 Windows 上无效
	mapStat, _ := disk.IOCounters()
	relut["io"] = mapStat
	//分区
	//调用disk.PartitionStat(all bool)函数，返回分区信息。如果all = false，只返回实际的物理分区（包括硬盘、CD-ROM、USB），忽略其它的虚拟分区。如果all = true则返回所有的分区。返回类型为[]PartitionStat，每个分区对应一个PartitionStat结构
	infos, _ := disk.Partitions(false) //实际的物理分区
	relut["device"] = infos
	//使用频率
	//调用disk.Usage(path string)即可获得路径path所在磁盘的使用情况，返回一个UsageStat结构
	path := utils.GetAbsPath()
	info, _ := disk.Usage(path) //指定路径
	relut["usage"] = info
	info3, _ := disk.IOCounters() //所有硬盘的io信息
	relut["usage_all"] = info3

	return relut
}

// MoniterHost host主机	子包host可以获取主机相关信息，如开机时间、内核版本号、平台信息
func MoniterHost() map[string]interface{} {
	relut := map[string]interface{}{}
	//开机时间 host.BootTime()返回主机开机时间的时间戳
	timestamp, _ := host.BootTime()
	t := time.Unix(int64(timestamp), 0)
	relut["systemBootTime"] = t.Local().Format("2006-01-02 15:04:05")
	//内核和平台信息
	platform, family, version, _ := host.PlatformInformation()
	relut["version"] = version
	relut["platform"] = platform
	relut["family"] = family
	//终端用户信息	host.Users()返回终端连接上来的用户信息，每个用户一个UserStat
	users, _ := host.Users()
	relut["terminalUser"] = users

	return relut
}

// MoniterMem 内存
func MoniterMem() map[string]interface{} {
	relut := map[string]interface{}{}
	memInfo, err := mem.VirtualMemory()
	if err != nil {
		global.GVA_LOG.Error("get memory info fail. err： ", zap.Error(err))
		return nil
	}
	// 获取总内存大小，单位GB
	memTotal := memInfo.Total / 1024 / 1024 / 1024
	// 获取已用内存大小，单位MB
	memUsed := memInfo.Used / 1024 / 1024
	// 可用内存大小
	memAva := memInfo.Available / 1024 / 1024
	// 内存可用率
	memUsedPercent := memInfo.UsedPercent
	relut["virtualMemTotal"] = memTotal
	relut["virtualMemUsed"] = memUsed
	relut["virtualMemAva"] = memAva
	relut["virtualMemUsedPercent"] = memUsedPercent
	swapMemory, _ := mem.SwapMemory()
	relut["swapMemoryTotal"] = swapMemory.Total / 1024 / 1024 / 1024
	relut["swapMemoryUsed"] = swapMemory.Used / 1024 / 1024
	relut["swapMemoryFree"] = swapMemory.Free / 1024 / 1024
	relut["swapMemoryUsedPercent"] = swapMemory.UsedPercent
	return relut
}

// MoniterLoad 系统负载
func MoniterLoad() map[string]interface{} {
	relut := map[string]interface{}{}
	loadInfo, err := load.Avg()
	if err != nil {
		global.GVA_LOG.Error("get average load fail. err: ", zap.Error(err))
		return nil
	}
	relut["loadAvg"] = loadInfo
	return relut
}
func GetLocalIP() (ip string, err error) {
	addrs, err := net.InterfaceAddrs()
	if err != nil {
		return
	}
	for _, addr := range addrs {
		ipAddr, ok := addr.(*net.IPNet)
		if !ok {
			continue
		}
		if ipAddr.IP.IsLoopback() {
			continue
		}
		if !ipAddr.IP.IsGlobalUnicast() {
			continue
		}
		return ipAddr.IP.String(), nil
	}
	return
}
